import time
import random
import string
from urllib.parse import quote
import hashlib
import urllib
import urllib.request as request
import json


class BaseClass:
    def __init__(self, url):
        """
        :param url:api的访问地址
        """
        self.URL = url;
        self.APP_ID = 2172873624;  # 你自己的app_id
        self.APP_KEY = "POR1S1IKFoivbUav";  # 你自己的app_key

        # params属性需要用户后来修改，添加对应api所需的参数
        # 这里列举出的参数都是共有的，特有的参数需要用户自己传入
        self.params = {
            'app_id': self.APP_ID,
            'time_stamp': None,
            'nonce_str': None,
        };

        # 调用接口返回的结果
        self.result = None;

    def __get_sign(self):
        """
        计算获得sign的方法
        :return:None
        """
        # 获得时间戳(秒级)，防止请求重放
        time_stamp = int(time.time());

        # 获得随机字符串，保证签名不被预测
        nonce_str = ''.join(random.sample(string.ascii_letters + string.digits, 10))

        # 组合参数（缺少sign，其值要根据以下获得）
        self.params['time_stamp'] = time_stamp;
        self.params['nonce_str'] = nonce_str;

        # 计算获得sign的值
        before_sign = '';
        # 对key排序拼接
        for key in sorted(self.params):
            before_sign += f'{key}={quote(str(self.params[key]).encode("utf-8"))}&';

        # 将应用秘钥以app_key为键名，拼接到before_sign的末尾
        before_sign += f"app_key={self.APP_KEY}";

        # 对获得的before_sign进行MD5加密（结果大写），得到借口请求签名
        sign = hashlib.md5(before_sign.encode("utf-8")).hexdigest().upper();

        # 将请求签名添加进参数字典
        self.params["sign"] = sign;

    def get_result(self):
        """
        该方法用于调用api，获得返回的结果
        :return: None
        """
        # 完善params参数，将sign添加进参数字典
        self.__get_sign();

        params = urllib.parse.urlencode(self.params).encode("utf-8");
        req = request.Request(url=self.URL, data=params);

        # 设置超时10秒，重试3次
        count = 0;
        while True:
            try:
                count += 1;
                self.result = request.urlopen(req, timeout=10);
                break;
            except Exception as e:
                print(e)
                print(f"连接超时，正在进行第{str(count)}次重连")
                if count <= 3:
                    continue;
                else:
                    break;

    def do_result(self):
        """
        处理结果的方法
        :return: None
        """
        pass;

    def run(self):
        """
        主运行方法
        :return: None
        """
        pass;


class TencetChat(BaseClass):
    def __init__(self, question):

        super(TencetChat, self).__init__("https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat");
        self.params["session"] = "10000"  # 这个是我随便写的，可以使用。
        self.question = question;

    def deal_question(self):
        """
                对提出的问题进行处理，限制长度和类型
                :return: None
                """
        if not isinstance(self.question, str):
            raise TypeError(f"question参数必须是 ‘str’ 类型的，不能是 ‘{type(self.question)}’ 类型的！！！");
        else:
            if len(self.question.encode("utf-8")) > 300:
                raise ValueError("question参数的长度必须小于300个字节（utf-8格式下）")
            else:
                self.params["question"] = self.question;
                self.do_result();

    def do_result(self):
        self.get_result();
        if self.result:
            res = json.loads(self.result.read().decode("utf-8"));
            # print(res)
            if not res["msg"] == "ok":
                self.answer = "我好像出错了：" + res["msg"];
            else:
                self.answer = res["data"]["answer"];
        else:
            self.answer = "我尝试了4次，但还是失败了，只能说我尽力了。";

    def run(self):
        self.deal_question();

def chat(msg):
    chat = TencetChat(msg)
    chat.run()
    return chat.answer


if __name__ == '__main__':
    chat = TencetChat("泰州天气");
    chat.run();
    print("智能闲聊：" + chat.answer);

